package pikasial.images;

import java.awt.Dimension;
import java.awt.image.BufferedImage;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;

import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.metadata.MetadataException;

import pikasial.images.traitements.RescaleTraitement;
import pikasial.utils.ExtensionsImages;

/**
 * Représente une image utilisée par l'application.
 * <p>
 * Une image correspond à un fichier sur le disque. Elle hérite donc de
 * pikasial.fs.Fichier
 *
 * Enfin, une image est bien sûr définie par une vignette et une image.
 * La vignette est un attribut de la classe, mais elle n'est crée que peu avant
 * son utilisation (ensuite, elle reste). En effet, la création de la vignette
 * est une opération longue et si la vignette était crée à l'instanciation
 * de la classe, la manipulation de collections de PikImage serait très longue
 * et peu réactive. L'image quant à elle n'est lue sur le disque que lorsqu'on
 * en a besoin, c'est-à-dire pour l'afficher.
 * En effet, s'il s'agissait d'un attribut de la classe, l'application
 * se retrouverait bien vite à court de mémoire.
 *
 * @author ESIAL - Groupe 14
 */
public final class PikImage extends pikasial.fs.Fichier {

    /**
     * La vignette de l'image.
     * <p>
     * Crée par le premier appel de getVignette()
     */
    protected BufferedImage thumbnail = null;
    /** Informations complémentaires. */
    /** Largeur des vignettes. */
    public static final int THUMB_WIDTH = 130;
    /** Hauteur des vignettes. */
    public static final int THUMB_HEIGHT = 120;
    protected Dimension dims;
    protected Date modifDate;
    protected String commentaire;
    protected EXIFData exifData;
    protected TagsImage tags;
    protected int type;


    /** Crée une image à partir du fichier spécifié en paramètre.
     *
     * @param f - le fichier contenant l'image
     */
    public PikImage(final File f) {
        super(f);
        name = f.getName();
        tags = new TagsImage();
        modifDate = new Date(f.lastModified());
        String ext = ExtensionsImages.getExtensionFichier(f).toLowerCase();
        type = ExtensionsImages.getExtensionType(ext);
    }

    /**
     * Crée une image à partir du chemin spécifié.
     *
     * @param path - le chemin du fichier contenant l'image
     */
    public PikImage(final String path) {
        this(new File(path));
    }

    public Dimension getDimensions() throws IOException {
    	if (dims == null) {
    		BufferedImage bi = getImage();
    		dims = new Dimension(bi.getWidth(),bi.getHeight());
    		bi = null;
    	}
    	return dims;
    }

    /**
     * Teste si le fichier est une image.
     *
     * @return vrai
     */
    @Override
    public boolean containsImage() {
        return true;
    }

    /**
     * Lit l'image sur le disque, et la retourne.
     * <p>
     * L'image n'est lue qu'à la demande, pour préserver la
     * mémoire.
     *
     * @return l'image correspondant à cette instance
     * @throws IOException - impossible de lire le fichier
     */
    public BufferedImage getImage() throws IOException {
        return ImageIO.read(super.file);
    }

    /**
     * Crée la vignette de l'image lors du premier appel, et la
     * retourne.
     * @return la vignette de l'image
     */
    public ImageIcon getVignetteIcon() throws IOException {
        if (thumbnail == null) {
            loadVignette();
        }
        return new ImageIcon(thumbnail);
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isVignetteLoaded() {
        return thumbnail != null;
    }

    public void resetVignette() {
        thumbnail = null;
    }

    public void loadVignette() throws IOException {
        if (thumbnail == null) {
            BufferedImage bi;
            String[] exts = ImageIO.getReaderFileSuffixes();
//            String[] exts = ImageIO.getReaderFormatNames();
            String ext = ExtensionsImages.getExtensionFichier(file).toLowerCase();
            boolean trouve = false;
            for (int i = 0; i < exts.length && !trouve; i++) {
                if (exts[i].equals(ext)) {
                    trouve = true;
                }
            }
            if (!trouve) {
                throw new IOException("Impossible d'ouvrir le fichier "
                    + getPath()
                    + "! Format non supporté.");
            }
            File f = new File(pikasial.Configuration.getInstance().getProperty(pikasial.Configuration.THUMB_FOLDER_PROP)
                + hashCode() + "." + ext);
            if (f.exists()) {
                System.out.println("Recupération sauvegarde " + f.getName());
                thumbnail = ImageIO.read(f);
            } else {
                bi = ImageIO.read(file);
                dims = new Dimension(bi.getWidth(),bi.getHeight());
                double rapportHL = ((double) bi.getWidth()) / bi.getHeight();

                double sc;
                if (rapportHL >= 1.0) {
                    sc = ((double) THUMB_WIDTH) / bi.getWidth();
                } else {
                    sc = ((double) THUMB_HEIGHT) / bi.getHeight();
                }
                if (sc < 1) {
                    RescaleTraitement rt = new RescaleTraitement(bi, sc, sc);
                    thumbnail = rt.executeTraitement();
                } else {
                    thumbnail = bi;
                }
            }
        }
    }

    public Date getDateModification() { return modifDate; }
    public void setDateModification(Date d) { modifDate = d; }

    public void setCommentaire(String comment) { this.commentaire = comment; }
    public String getCommentaire() { return commentaire; }

    public Date getDatePrise() throws IncompatibleImageFormatException,
    	JpegProcessingException, IOException, MetadataException {
    	if (exifData == null)
    		exifData = new EXIFData(this);
    	return exifData.getDatePrise();
    }

    public EXIFData getExifData() throws IncompatibleImageFormatException,
    	JpegProcessingException, IOException, MetadataException {
    	if (exifData == null) {
    		 exifData = new EXIFData(this);
    	}
    	return exifData;
    }

    public TagsImage getTags() { return tags; }

    public int getType() { return type; }

    @Deprecated
    public int getHeight() throws JpegProcessingException,
    	MetadataException, IncompatibleImageFormatException {
    	if (exifData == null)
    		exifData = new EXIFData(this);
    	return exifData.getImageHeight();
    }

    @Deprecated
    public int getWidth() throws JpegProcessingException,
    	MetadataException, IncompatibleImageFormatException {
    	if (exifData == null)
    		exifData = new EXIFData(this);
    	return exifData.getImageWidth();
    }

    public BufferedImage getVignette() throws IOException {
        if (thumbnail == null) {
            loadVignette();
        }
        return thumbnail;
    }
}
